gusucode.com > VC 电梯管理系统 > VC 电梯管理系统/gusucode/Elevator/MainDlg.cpp
//Download by http://www.NewXing.com // MainDlg.cpp : implementation file // #include "stdafx.h" #include "Elevator.h" #include "MainDlg.h" #include "math.h" #include "Splash.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif /*#################################################################### 模块名称: 主控中心 开发作者: 漫步阳光 开发时间: @2005.11 ####################################################################*/ ///////////////////////////////////////////////////////////////////////////// // CMainDlg dialog CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/) : CDialog(CMainDlg::IDD, pParent) { //{{AFX_DATA_INIT(CMainDlg) //}}AFX_DATA_INIT try { CreateDirectory("logs",NULL);//创建存放日志的目录 }catch(CException* e){ AfxMessageBox("无法创建日志目录,可能是没有权限。\n\n因此本系统日志功能将失效。但不会影响系统正常运行。"); } try{ m_cLogFile.Open("logs\\log0.txt", CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite\ | CFile::typeText , &m_Except);//打开日志文件 m_cLogFile.SeekToEnd(); }catch(CException* e){} str_arrElevatorName[0]='A'; str_arrElevatorName[1]='B'; str_arrElevatorName[2]='C'; str_arrElevatorName[3]='D'; iTotalFailTimes = 0; } void CMainDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMainDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CMainDlg, CDialog) //{{AFX_MSG_MAP(CMainDlg) ON_WM_DESTROY() ON_BN_CLICKED(IDC_BTN_ABOUT, OnBtnAbout) ON_WM_TIMER() ON_WM_CREATE() //}}AFX_MSG_MAP ON_COMMAND_RANGE(IDC_FLOORBUTTONS,IDC_FLOORBUTTONS+20,OnFloorBtnClk) ON_MESSAGE(WM_ARRIVE_ONEFLOOR,OnOneFloorArrived) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMainDlg message handlers void CMainDlg::OnDestroy() { CDialog::OnDestroy(); // TODO: Add your message handler code here for(int i=0;i<ELEVATOR_NUM;i++) { delete m_elevatorArr[i]; } for(i=0;i<FLOOR_NUM;i++) { delete m_pFloorButton[i][0]; delete m_pFloorButton[i][1]; } KillTimer(1); lWaitQueue.~CircleSingleLink(); try{ Write2Log("系统成功关闭..."); m_cLogFile.Close(); }catch(CException* e){} } BOOL CMainDlg::OnInitDialog() { CDialog::OnInitDialog(); //让窗体呆在最上层:) //SetWindowPos(&this->wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); // TODO: Add extra initialization here //===========创建动态楼层按钮 CString strCaption; int iPanelLeft = 795; int iPanelTop = 70; int iColWidth = 60; int iRowHeight = 60; int iBtnWidth = 55; int iBtnHeight = 25; int i; try{ for(i=FLOOR_NUM;i>0;i--) { strCaption.Format("%d",i); m_pFloorButton[i-1][0]=new CButton; m_pFloorButton[i-1][1]=new CButton; m_pFloorButton[i-1][0]->Create(strCaption+"↑",BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,\ CRect(\ iPanelLeft,\ iPanelTop+(10-i)*iRowHeight/2,\ iPanelLeft+iBtnWidth,\ iPanelTop+(10-i)*iRowHeight/2+iBtnHeight),\ this,IDC_FLOORBUTTONS+2*(i-1));//left,top,right,bottom m_pFloorButton[i-1][1]->Create(strCaption+"↓",BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,\ CRect(\ iPanelLeft+iColWidth,\ iPanelTop+(10-i)*iRowHeight/2,\ iPanelLeft+iColWidth+iBtnWidth,\ iPanelTop+(10-i)*iRowHeight/2+iBtnHeight),\ this,IDC_FLOORBUTTONS+2*(i-1)+1);//left,top,right,bottom }//for }catch(CException* e){ AfxMessageBox("无法创建楼层按钮,程序不能正常运行。"); return FALSE;//退出! } //隐藏掉两个无用的按钮 m_pFloorButton[9][0]->ShowWindow(FALSE); m_pFloorButton[0][1]->ShowWindow(FALSE); try{ for(i=0;i<ELEVATOR_NUM;i++) { m_elevatorArr[i] = new CElevatorDlg(i+1,MAX_PASSENGER_NUM,(1+i*2)%FLOOR_NUM,this); m_elevatorArr[i]->Create(IDD_ELEVATOR_DIALOG,this); m_elevatorArr[i]->MoveWindow(CRect(i*195,0,(i+1)*195,500)); m_elevatorArr[i]->ShowWindow(SW_SHOW); } }catch(CException* e){ AfxMessageBox("无法创建电梯,程序不能正常运行。"); return FALSE;//退出! } Write2Log("系统成功启动..."); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } /*#################################################################### // name: OnFloorBtnClk // input1: UINT curBtn 楼层按钮序号 // ouput: void // 功能描述: 响应楼层按钮的动作 // 开发作者: 漫步阳光 // 开发时间: @2005.11 // 版本说明: v1.0 ####################################################################*/ void CMainDlg::OnFloorBtnClk(UINT curBtn) { // TODO: Add your control notification handler code here int iReqFloor =curBtn-1100+1; sOuterRequest tmpOuterRequest = No2ReqStruct(iReqFloor); if((lWaitQueue.searchNode(tmpOuterRequest)) > 0) { AfxMessageBox("请不要重复请求。"); return; } /* //将请求加入队列 if(!(lWaitQueue.appendTail(tmpOuterRequest))) { AfxMessageBox("无法将您的请求加入请求队列,请稍后再试。"); return; } */ GetDlgItem(curBtn)->EnableWindow(FALSE); trytoSchedule(tmpOuterRequest);//立即尝试分派! } void CMainDlg::OnCancel() { // TODO: Add extra cleanup here if(IDYES==MessageBox("是否真的结束?","电梯系统",MB_YESNO)) CDialog::OnCancel(); } /*#################################################################### // name: No2ReqStruct // input1: int iNo 楼层按钮序号 // ouput: sOuterRequest 该按钮对应的楼层和方向结构体 // 功能描述: 将楼层按钮序号转换成对应的楼层和方向 // 开发作者: 漫步阳光 // 开发时间: @2005.11 // 版本说明: v1.0 ####################################################################*/ sOuterRequest CMainDlg::No2ReqStruct(int iNo) { sOuterRequest tempVal; if(iNo%2==0) { tempVal.eReqDirection =DOWN; } else { tempVal.eReqDirection =UP; iNo++; } tempVal.iReqFloor = iNo/2; tempVal.iAge =0; tempVal.bReClaimed = FALSE; return tempVal; } int CMainDlg::ReqStruct2No(const sOuterRequest& tmpRequest) { return (tmpRequest.eReqDirection==UP) ? (2*(tmpRequest.iReqFloor-1)) : (2*(tmpRequest.iReqFloor-1)+1); } /*#################################################################### // name: Goodness // input1: sOuterRequest tmpOuterRequest 用户请求结构体 // ouput: int 找到的最佳接收电梯(优先数最小的)的ID // 功能描述: 为用户请求寻找一个最佳接收电梯 // 开发作者: 漫步阳光 // 开发时间: @2005.11 // 版本说明: v1.0 ####################################################################*/ int CMainDlg::Goodness(const sOuterRequest& tmpOuterRequest) { int returnVal = -1; //挨个查看各正常电梯的状态 int tmpCurFloor; int tmpCurWeight; int tmpPrioValue; bool tmpCanSchedule; enum state tmpState; int iPrioValue = 10000;//优先数,优先数越小优先级越大 for(int i=0;i<ELEVATOR_NUM; i++) { tmpState = m_elevatorArr[i]->getState(); tmpCurFloor = m_elevatorArr[i]->getCurFloor(); tmpCurWeight = m_elevatorArr[i]->getCurWeight(); tmpCanSchedule = m_elevatorArr[i]->canSchedule(); if(tmpState!=MAL_FUNCTION && tmpCanSchedule) { if(tmpState==IDLE || \ (tmpOuterRequest.eReqDirection==UP && (tmpState==UP_RUN || tmpState==UP_PAUSE)) || \ (tmpOuterRequest.eReqDirection==DOWN && (tmpState==DOWN_RUN || tmpState==DOWN_PAUSE)) ) { if(tmpState==IDLE) { //计算该电梯的优先数 tmpPrioValue = DIST_PRIO*abs(tmpOuterRequest.iReqFloor-tmpCurFloor)+\ WEIGHT_PRIO*tmpCurWeight; if(tmpPrioValue<iPrioValue) { iPrioValue = tmpPrioValue; returnVal = i; } } if(tmpOuterRequest.eReqDirection==UP && tmpOuterRequest.iReqFloor>=tmpCurFloor) { //计算该电梯的优先数 tmpPrioValue = DIST_PRIO*(tmpOuterRequest.iReqFloor-tmpCurFloor)+\ WEIGHT_PRIO*tmpCurWeight; if(tmpPrioValue<iPrioValue) { iPrioValue = tmpPrioValue; returnVal = i; } } if(tmpOuterRequest.eReqDirection==DOWN && tmpOuterRequest.iReqFloor<=tmpCurFloor) { //计算该电梯的优先数 tmpPrioValue = DIST_PRIO*(tmpCurFloor-tmpOuterRequest.iReqFloor)+\ WEIGHT_PRIO*tmpCurWeight; if(tmpPrioValue<iPrioValue) { iPrioValue = tmpPrioValue; returnVal = i; } } } } }//for return returnVal; } /*#################################################################### // name: Schedule // input1: // ouput: void // 功能描述: 定时处理主控中心请求队列中请求 // 开发作者: 漫步阳光 // 开发时间: @2005.11 // 版本说明: v1.0 // 行为说明: 该函数被周期性激活,以定时分发请求队列中的请求 该函数在队列空时停止定时器并直接返回,否则 对于当前等待队列中的每个请求尝试分发:: 将成功分发出去的请求删除,未成功分发的做好标记并增加年龄后重新放回队列 对于年龄大于一定值(也就是超过一定时间仍未得到分派)的请求则直接删除 ####################################################################*/ void CMainDlg::Schedule() { if(lWaitQueue.getLength() == 0) { KillTimer(1);//队列空了,歇会 return; } int iReqFloor; CString tempString,tempString1; sOuterRequest tmpOuterRequest; while(lWaitQueue.cutHead(tmpOuterRequest) && !tmpOuterRequest.bReClaimed) { if(tmpOuterRequest.iAge < BAD_REQUEST_AGE)//如果此请求长时间没有得到分配,则直接删除 { trytoSchedule(tmpOuterRequest); } else//对于长时间不能调度出去的请求也要处理一下后事:( { iReqFloor = ReqStruct2No(tmpOuterRequest);//转换成请求按钮号 GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->EnableWindow(TRUE); iTotalFailTimes++;//递增总调度失败次数 tempString.Format("%d",tmpOuterRequest.iReqFloor); tempString1 = (tmpOuterRequest.eReqDirection==UP) ? "↑":"↓"; AfxMessageBox("很抱歉,下面的请求因超时而被系统取消,请重新请求。\r\n"+tempString+tempString1); } } //将本次追加到队尾的请求标识位恢复 if(tmpOuterRequest.bReClaimed){ tmpOuterRequest.bReClaimed = FALSE; lWaitQueue.appendTail(tmpOuterRequest); } lWaitQueue.refreshLink(); } void CMainDlg::trytoSchedule(sOuterRequest& tmpRequest) { int targetElevator=-1,iReqFloor; CString tempString,tempString1; if((targetElevator = Goodness(tmpRequest))<0)//目前没有找到合适的接受者,再放入 { tmpRequest.iAge++; tmpRequest.bReClaimed = TRUE; lWaitQueue.appendTail(tmpRequest); } else //发消息给目标电梯 { //对于电梯刚好在当前楼层的情况,电梯的返回往往比下面的程序段还要快! //所以此段程序不能跟下面的那行调换位置!!! tempString1.Format("%c",str_arrElevatorName[targetElevator]); iReqFloor = ReqStruct2No(tmpRequest);//转换成请求按钮号 GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->GetWindowText(tempString); GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->SetWindowText(tempString+"("+tempString1+")"); m_elevatorArr[targetElevator]->acceptReq(tmpRequest); } KillTimer(1); SetTimer(1,SCHEDULE_INTERVAL*1000,NULL);//启动主控中心调度定时器 } void CMainDlg::OnBtnAbout() { ::AfxMessageBox("关于本电梯系统", MB_USERDEFINE); } void CMainDlg::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default switch(nIDEvent) { case 1: Schedule(); break; } CDialog::OnTimer(nIDEvent); } LONG CMainDlg::OnOneFloorArrived(WPARAM wP,LPARAM lP) { int iReqFloor=(int)wP; CString tempString; GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->EnableWindow(TRUE); GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->GetWindowText(tempString); if(tempString.GetLength() >4 ) { tempString = tempString.Mid(0,tempString.GetLength()-3); GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->SetWindowText(tempString); } //Invalidate(); //重画窗体 return 0; } void CMainDlg::Write2Log(const CString& content) { // TODO: Add your control notification handler code here if(content=="") return; CTime m_SysTime = CTime::GetCurrentTime(); try{ m_cLogFile.WriteString(content+"\t("+m_SysTime.Format("%Y-%m-%d %H:%M:%S")+")\n"); }catch(CException* e){} } int CMainDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDialog::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your specialized creation code here CSplashWnd::ShowSplashScreen(this); //显示启动画面 return 0; }